﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using ICSharpCode.SharpZipLib.BZip2;
using ICSharpCode.SharpZipLib.GZip;

namespace Netfraction.Network.Protocol.BZIP
{
    [ProtocolFeature(Name = "BZIP")]
    public class ProtocolFeatureBZIP : ProtocolFeature, IProtocolFileListFeature
    {
        private const string FILE_LIST_NAME = "files.xml.bz2";

        public ProtocolFeatureBZIP()
        {
            ShareManager.ShareManager sManager = ShareManager.ShareManager.GetInstance();
            lock (sManager)
            {
                sManager.RegisterFileListName(FILE_LIST_NAME, this);
            }
        }

        #region IProtocolFileListFeature Members

        MemoryStream IProtocolFileListFeature.WriteToFileList(MemoryStream stream)
        {
            ShareManager.ShareManager sManager = ShareManager.ShareManager.GetInstance();
            string baseListName = GetBASEListName(sManager);

            if (string.IsNullOrEmpty(baseListName))
            {
                return null;
            }

            stream = sManager.CreateFileListStream(baseListName);
            if (stream == null)
            {
                return null;
            }
            
            // run bzip algorithm...
            MemoryStream bZippedStream = new MemoryStream();
            ICSharpCode.SharpZipLib.BZip2.BZip2.Compress(stream, bZippedStream, 9); // mBlock size is 9, the strongest compression - why isn't this hidden inside the BZip2 library?

            return new MemoryStream(bZippedStream.ToArray());   // must create a new stream here, the one inside the function will be disposed since it loses scope.
        }

        private static string GetBASEListName(ShareManager.ShareManager sManager)
        {
            string baseListName = string.Empty;

            lock (sManager)
            {
                // BASE was most likely added first and this will only go through one iteration
                foreach (string name in sManager.FileListNames)
                {
                    if (name != FILE_LIST_NAME) // avoid creating an infinite loop below
                    {
                        baseListName = name;
                        break;
                    }
                }
            }
            return baseListName;
        }

        MemoryStream IProtocolFileListFeature.ReadFromFileList(MemoryStream stream)
        {
            Console.WriteLine("BZIP list reader");
            MemoryStream unZippedStream = new MemoryStream();
            ICSharpCode.SharpZipLib.BZip2.BZip2.Decompress(stream, unZippedStream);

            ShareManager.ShareManager sManager = ShareManager.ShareManager.GetInstance();
            string baseListName = GetBASEListName(sManager);

            if (string.IsNullOrEmpty(baseListName))
            {
                return null;
            }

            return sManager.ReadFileListFromStream(baseListName, new MemoryStream(unZippedStream.ToArray()));
        }
        
        #endregion
    }
}
